﻿using System;
using System.Data;
using System.Drawing;
using System.Linq;
using System.Windows.Forms;

/* Урок "4D моделирование." */
 
namespace Model4D
{
    public partial class frmMain : Form
    {
        public frmMain()
        {
            InitializeComponent();
        }

        #region === members ===

        Bitmap _bitmap = null;
        AbstractMultiDimModel _model = null;
        ModelTransformer _transformer = null;
        Matrix _matrix = null;
        Timer _timer = null;

        CheckBox[] _checkBoxes = null;

        #endregion

        #region === private ===

        void CreateCheckBoxList()
        {
            _checkBoxes = new CheckBox[6];

            int index = -1;
            int c_xPos = pictureBox1.Location.X + pictureBox1.Width + 20;
            const int c_yPos = 16;
            const int c_yShift = 2;

            // 1
            _checkBoxes[++index] = new CheckBox();
            _checkBoxes[index].Location = new Point(c_xPos, c_yPos);
            _checkBoxes[index].Name = string.Format("checkBox{0}", index + 1);
            _checkBoxes[index].Text = "Поворот  XY";
            _checkBoxes[index].Checked = true;

            // 2
            _checkBoxes[++index] = new CheckBox();
            _checkBoxes[index].Location = new Point(c_xPos, _checkBoxes[index - 1].Location.Y + _checkBoxes[index - 1].Size.Height + c_yShift);
            _checkBoxes[index].Name = string.Format("checkBox{0}", index + 1);
            _checkBoxes[index].Text = "Поворот  XZ";
            _checkBoxes[index].Checked = true;

            // 3
            _checkBoxes[++index] = new CheckBox();
            _checkBoxes[index].Location = new Point(c_xPos, _checkBoxes[index - 1].Location.Y + _checkBoxes[index - 1].Size.Height + c_yShift);
            _checkBoxes[index].Name = string.Format("checkBox{0}", index + 1);
            _checkBoxes[index].Text = "Поворот  XU";
            _checkBoxes[index].Checked = true;

            // 4
            _checkBoxes[++index] = new CheckBox();
            _checkBoxes[index].Location = new Point(c_xPos, _checkBoxes[index - 1].Location.Y + _checkBoxes[index - 1].Size.Height + c_yShift);
            _checkBoxes[index].Name = string.Format("checkBox{0}", index + 1);
            _checkBoxes[index].Text = "Поворот  YZ";
            _checkBoxes[index].Checked = true;

            // 5
            _checkBoxes[++index] = new CheckBox();
            _checkBoxes[index].Location = new Point(c_xPos, _checkBoxes[index - 1].Location.Y + _checkBoxes[index - 1].Size.Height + c_yShift);
            _checkBoxes[index].Name = string.Format("checkBox{0}", index + 1);
            _checkBoxes[index].Text = "Поворот  YU";
            _checkBoxes[index].Checked = true;

            // 6
            _checkBoxes[++index] = new CheckBox();
            _checkBoxes[index].Location = new Point(c_xPos, _checkBoxes[index - 1].Location.Y + _checkBoxes[index - 1].Size.Height + c_yShift);
            _checkBoxes[index].Name = string.Format("checkBox{0}", index + 1);
            _checkBoxes[index].Text = "Поворот  ZU";
            _checkBoxes[index].Checked = false;

            for (int i = 0; i < _checkBoxes.Length; i++)
            {
                _checkBoxes[i].CheckedChanged += FrmMain_CheckedChanged;
            }

            this.Controls.AddRange(_checkBoxes);
        }

        bool[] CheckCollection => _checkBoxes.Select(x => x.Checked).ToArray();

        Matrix CreateMatrix(bool[] bRotate, ModelTransformer transformer, int Dimention)
        {
            const double angle = 0.02;

            transformer.Begin(Dimention);

            if (bRotate[0])
                transformer.Transform(TransformEnum.RotateXY, angle);

            if (bRotate[1])
                transformer.Transform(TransformEnum.RotateXZ, angle * 0.8);

            if (bRotate[2])
                transformer.Transform(TransformEnum.RotateXU, angle * 0.75);

            if (bRotate[3])
                transformer.Transform(TransformEnum.RotateYZ, angle);

            if (bRotate[4])
                transformer.Transform(TransformEnum.RotateYU, angle * 0.55);

            if (bRotate[5])
                transformer.Transform(TransformEnum.RotateZU, angle);

            return transformer.End();
        }

        void TransformModel(Matrix matrix, AbstractMultiDimModel model)
        {
            foreach (Vector modelVector in model.Vectors)
            {
                Vector v = matrix * modelVector;
                modelVector.X = v.X;
            }
        }

        void RenderModel(Graphics g, AbstractMultiDimModel model)
        {
            PointF[] points = model.GetPoints(_bitmap.Width / 2, _bitmap.Height / 2);
            Pen pen = new Pen(Color.Black, 2.0f);

            // рисуем каркас модели.
            for (int i = 0; i < points.Length / 2; i++)
            {
                g.DrawLine(pen, points[2 * i + 0], points[2 * i + 1]);
            }
        }

        void Render()
        {
            // проверка картинки на валидность.
            if (_bitmap == null)
                return;

            // создаем новый графический контекст.
            using (Graphics g = Graphics.FromImage(_bitmap))
            {
                // очищаем контекст
                g.Clear(Color.White);

                // отрисовываем модель
                RenderModel(g, _model);
            }

            // отрисовка.
            pictureBox1.Image = _bitmap;
        }

        #endregion

        private void frmMain_Load(object sender, EventArgs e)
        {
            pictureBox1.Dock = DockStyle.Fill;
            pictureBox1.BackColor = Color.White;
            CreateCheckBoxList();

            _bitmap = new Bitmap(pictureBox1.Width, pictureBox1.Height, System.Drawing.Imaging.PixelFormat.Format24bppRgb);

            _model = new Cube4D(120);
            _transformer = new ModelTransformer();
            _matrix = CreateMatrix(CheckCollection, _transformer, _model.Dimention);

            _timer = new Timer
            {
                Interval = 25
            };
            _timer.Tick += Timer_Tick;
            _timer.Start();
        }

        private void Timer_Tick(object sender, EventArgs e)
        {
            TransformModel(_matrix, _model);
            Render();
        }

        private void frmMain_FormClosed(object sender, FormClosedEventArgs e)
        {
            _timer.Stop();
        }

        private void frmMain_Paint(object sender, PaintEventArgs e)
        {
            Render();
        }

        private void pictureBox1_SizeChanged(object sender, EventArgs e)
        {
            if (pictureBox1.Width > 0 && pictureBox1.Height > 0)
            {
                _bitmap = new Bitmap(pictureBox1.Width, pictureBox1.Height, System.Drawing.Imaging.PixelFormat.Format24bppRgb);
            }
        }

        private void btnClose_Click(object sender, EventArgs e)
        {
            Close();
        }

        private void FrmMain_CheckedChanged(object sender, EventArgs e)
        {
            _matrix = CreateMatrix(CheckCollection, _transformer, _model.Dimention);
        }
    }
}
